package com.xxxtea.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxxtea.common.Result;
import com.xxxtea.common.UserContext;
import com.xxxtea.dto.*;
import com.xxxtea.entity.*;
import com.xxxtea.sdk.amap.AmapClient;
import com.xxxtea.service.*;
import com.xxxtea.util.CalUtils;
import com.xxxtea.util.ExcelUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 订单控制器
 *
 * 提供订单的完整管理功能，包括：
 * - 订单创建和支付
 * - 订单状态管理（发货、收货等）
 * - 配送费计算
 * - 库存管理和销量统计
 * - 支付二维码生成
 * - 订单数据导出
 *
 * 使用事务注解确保数据一致性
 * 使用Swagger注解进行API文档生成
 * 使用Lombok注解简化代码
 *
 * @author badman
 * @since 1.0.0
 */
@Slf4j
@Api("订单接口")
@RestController
@RequestMapping("/order")
@Transactional(rollbackFor = Exception.class)
public class OrderController {
	/**
	 * 高德地图客户端
	 */
	@Resource
	private AmapClient amapClient;
	
	/**
	 * 菜品服务
	 */
	@Resource
	private DishService dishService;
	
	/**
	 * 订单服务
	 */
	@Resource
	private OrderService orderService;
	
	/**
	 * 商家服务
	 */
	@Resource
	private MerchantService merchantService;
	
	/**
	 * 订单项服务
	 */
	@Resource
	private OrderItemService orderItemService;
	
	/**
	 * 旧物商品服务
	 */
	@Resource
	private SecondhandGoodsService secondhandGoodsService;

	/**
	 * 计算外卖配送费
	 * 根据用户位置和商家位置计算距离和配送费
	 *
	 * @param merchantId 商家ID
	 * @return 配送费金额
	 */
	@GetMapping("/calDeliveryFee")
	@Operation(summary = "外卖配送费计算")
	public Result<Double> calDeliveryFee(Integer merchantId) {
		Location location = merchantService.getById(merchantId).getLocation();
		double distance = amapClient.distance(UserContext.getUser().getLocation(), location);
		double deliveryFee = CalUtils.calculateDeliveryFee(distance);
		return Result.success(deliveryFee);
	}

	/**
	 * 创建订单
	 * 支持菜品和旧物两种业务类型
	 * 包含库存检查、价格计算、配送费计算等
	 *
	 * @param request 订单创建请求
	 * @return 操作结果
	 */
	@PostMapping("/create")
	@ApiOperation("创建订单")
	public Result<String> create(@RequestBody OrderRequest request) {
		List<ProductItem> items = request.getItems();
		OrderItem.BusinessType businessType = request.getBusinessType();

		// 构建商品ID和数量的映射
		Map<Integer, Integer> map = items.stream().collect(Collectors.toMap(ProductItem::getBusinessId, ProductItem::getCount));
		List<Integer> ids = CollUtil.map(items, ProductItem::getBusinessId, true);

		// 根据业务类型获取商品信息
		List<BaseProduct> productList;
		if (businessType == OrderItem.BusinessType.DISH) {
			List<Dish> dishList = dishService.listByIds(ids);
			productList = BeanUtil.copyToList(dishList, BaseProduct.class);
		} else {
			List<SecondhandGoods> goods = secondhandGoodsService.listByIds(ids);
			productList = BeanUtil.copyToList(goods, BaseProduct.class);
			for (BaseProduct product : productList) {
				product.setMerchantId(CollUtil.getFirst(goods).getSellerId());
			}
		}
		Assert.notEmpty(productList, "订单明细不能为空");

		// 计算总金额
		double total = productList.stream().mapToDouble(BaseProduct::getPrice).sum();

		// 菜品库存检查
		if (businessType == OrderItem.BusinessType.DISH) {
			for (BaseProduct product : productList) {
				Integer count = map.get(product.getId());
				Assert.isTrue(product.getStock() >= count, product.getName() + "库存不足，无法下单！");
			}
		}

		// 创建订单主表
		Order order = new Order();
		order.setBusinessType(businessType);
		order.setRemark(request.getRemark());
		order.setAddressId(request.getAddressId());
		order.setOrderNo(IdUtil.getSnowflakeNextIdStr());
		order.setTotalPrice(total);
		order.setStatus(Order.Status.ORDER);

		Integer merchantId = CollUtil.getFirst(productList).getMerchantId();
		order.setMerchantId(merchantId);
		// 菜品订单计算配送费
		if (businessType == OrderItem.BusinessType.DISH) {
			try {
				Location location = merchantService.getById(merchantId).getLocation();
				double distance = amapClient.distance(UserContext.getUser().getLocation(), location);
				double deliveryFee = CalUtils.calculateDeliveryFee(distance);
				order.setDeliveryFee(deliveryFee);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
		}
		orderService.save(order);

		// 创建订单子项
		List<OrderItem> orderItems = productList.stream().map(product -> {
			OrderItem orderItem = new OrderItem();
			orderItem.setMerchantId(product.getMerchantId());
			orderItem.setBusinessType(businessType);
			orderItem.setBusinessId(product.getId());
			orderItem.setUserId(order.getUserId());
			orderItem.setOrderId(order.getId());
			orderItem.setPrice(product.getPrice());
			orderItem.setName(product.getName());
			orderItem.setImage(product.getImage());
			orderItem.setCount(map.get(product.getId()));
			return orderItem;
		}).collect(Collectors.toList());

		// 保存订单明细
		orderItemService.saveBatch(orderItems);

		// 根据业务类型进行后续处理
		if (businessType == OrderItem.BusinessType.DISH) {
			// 菜品扣减库存，增加销量
			for (OrderItem orderItem : orderItems) {
				Integer count = orderItem.getCount();
				dishService.lambdaUpdate().eq(Dish::getId, orderItem.getBusinessId())
						.setIncrBy(Dish::getSales, count)
						.setDecrBy(Dish::getSales, count)
						.update();
			}
		} else {
			// 旧物状态改为已售
			for (OrderItem orderItem : orderItems) {
				secondhandGoodsService.lambdaUpdate().eq(SecondhandGoods::getId, orderItem.getBusinessId())
						.set(SecondhandGoods::getStatus, SecondhandGoods.Status.Status2)
						.update();
			}
		}
		return Result.success();
	}

	/**
	 * 支付订单
	 *
	 * @param id 订单ID
	 * @return 操作结果
	 */
	@GetMapping("/pay/{id}")
	@ApiOperation("支付订单")
	public Result<String> pay(@PathVariable String id) {
		Order order = orderService.getById(id);
		order.setStatus(Order.Status.PAY);
		orderService.updateById(order);
		return Result.success();
	}

	/**
	 * 订单发货
	 *
	 * @param request 发货请求信息
	 * @return 操作结果
	 */
	@PostMapping("/ship")
	@ApiOperation("订单发货")
	public Result<String> ship(@RequestBody ShipOrderRequest request) {
		Order order = orderService.getById(request.getOrderId());
		order.setDeliveryPerson(request.getDeliveryPerson());
		order.setDeliveryPhone(request.getDeliveryPhone());
		order.setStatus(Order.Status.SHIP);
		orderService.updateById(order);
		return Result.success();
	}

	/**
	 * 订单收货
	 *
	 * @param id 订单ID
	 * @return 操作结果
	 */
	@PostMapping("/receive/{id}")
	@ApiOperation("订单收货")
	public Result<String> receiving(@PathVariable String id) {
		Order order = orderService.getById(id);
		order.setStatus(Order.Status.FINISH);
		orderService.updateById(order);
		return Result.success();
	}

	/**
	 * 获取支付二维码
	 * 生成订单支付链接的二维码图片
	 *
	 * @param id 订单ID
	 * @param response HTTP响应对象
	 * @throws IOException IO异常
	 */
	@GetMapping("/qrCode/{id}")
	@ApiOperation("获取支付二维码")
	public void qrCode(@PathVariable String id, HttpServletResponse response) throws IOException {
		String host = SpringUtil.getProperty("server.host");
		String port = SpringUtil.getProperty("server.port");
		String url = StrUtil.format("http://{}:{}/api/order/pay/{}", host, port, id);
		byte[] bytes = QrCodeUtil.generatePng(url, new QrConfig());
		response.setContentType(MediaType.IMAGE_PNG_VALUE);
		response.getOutputStream().write(bytes);
	}

	@DeleteMapping("/{id}")
	@ApiOperation("删除订单")
	public Result<String> delete(@PathVariable String id) {
		if (!orderService.removeById(id)) {
			return Result.error("删除失败!");
		}
		return Result.success();
	}

	@PutMapping
	@ApiOperation("更新订单")
	public Result<String> update(@RequestBody Order request) {
		if (!orderService.updateById(request)) {
			return Result.error("更新失败!");
		}
		return Result.success();
	}

	@GetMapping("/{id}")
	@ApiOperation("获取单个订单")
	public Result<Order> getOne(@PathVariable String id) {
		Order order = orderService.getById(id);
		orderService.setOrderItems(Collections.singletonList(order));
		orderService.createPayCode(order);
		if (order.getBusinessType() == OrderItem.BusinessType.DISH) {
			order.setHasShipRole(order.getStatus() == Order.Status.PAY && UserContext.getRole() == User.Role.MERCHANT);
		} else {
			order.setHasShipRole(order.getStatus() == Order.Status.PAY && Objects.equals(UserContext.getId(), order.getMerchantId()));
		}
		return Result.success(order);
	}

	@GetMapping("/list")
	@ApiOperation("获取订单列表")
	public Result<List<Order>> list(Order request) {
		LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>(request);
		List<Order> orders = orderService.list(wrapper);
		orderService.setOrderItems(orders);
		return Result.success(orders);
	}

	@PostMapping("/page")
	@ApiOperation("分页查询订单")
	public Result<Page<Order>> page(@RequestBody PageQuery<Order> request) {
		// 分页查询
		LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>(request.getParam());
		wrapper.orderByDesc(Order::getId);
		Page<Order> pageResult = orderService.page(request.toPage(), wrapper);
		orderService.setOrderItems(pageResult.getRecords());
		return Result.success(pageResult);
	}

	@PostMapping("/export")
	@ApiOperation("导出订单数据")
	public void exportExcel(@RequestBody PageQuery<Order> query, HttpServletResponse response) throws Exception {
		// 分页查询
		LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>(query.getParam());
		Page<Order> page = orderService.page(query.toPage(), wrapper);
		// 执行导出
		ExcelUtils.exportExcel(response, page.getRecords(), Order.class, "订单数据");
	}
}
